#ifndef JFUTURE_H
#define JFUTURE_H

#include "jconcurrent_global.h"
#include "jconcurrentcompilertest.h"
#include "tools/jiterator.h"
#include "jfutureinterface.h"

template <typename T> class JFutureWatcher;
template <> class JFutureWatcher<void>;

template <typename T>
class JFuture
{
public:
    JFuture()
        : d(JFutureInterface<T>::canceledResult())
    { }
    explicit JFuture(JFutureInterface<T> *p) // internal
        : d(*p)
    { }
    JFuture(const JFuture &other)
        : d(other.d)
    { }
    ~JFuture()
    { }

    inline JFuture &operator=(const JFuture &other);
    bool operator==(const JFuture &other) const { return (d == other.d); }
    bool operator!=(const JFuture &other) const { return (d != other.d); }

    void cancel() { d.cancel(); }
    bool isCanceled() const { return d.isCanceled(); }

    void setPaused(bool paused) { d.setPaused(paused); }
    bool isPaused() const { return d.isPaused(); }
    void pause() { setPaused(true); }
    void resume() { setPaused(false); }
    void togglePaused() { d.togglePaused(); }

    bool isStarted() const { return d.isStarted(); }
    bool isFinished() const { return d.isFinished(); }
    bool isRunning() const { return d.isRunning(); }

    int resultCount() const { return d.resultCount(); }
    int progressValue() const { return d.progressValue(); }
    int progressMinimum() const { return d.progressMinimum(); }
    int progressMaximum() const { return d.progressMaximum(); }
    std::string progressText() const { return d.progressText(); }
    void waitForFinished() { d.waitForFinished(); }

    inline T result() const;
    inline T resultAt(int index) const;
    bool isResultReadyAt(int resultIndex) const { return d.isResultReadyAt(resultIndex); }

    operator T() const { return result(); }
    jlist<T> results() const { return d.results(); }

    class const_iterator
    {
    public:
        typedef std::bidirectional_iterator_tag iterator_category;
        typedef jptrdiff difference_type;
        typedef T value_type;
        typedef const T *pointer;
        typedef const T &reference;

        inline const_iterator() {}
        inline const_iterator(JFuture const * const _future, int _index) : future(_future), index(_index) {}
        inline const_iterator(const const_iterator &o) : future(o.future), index(o.index)  {}
        inline const_iterator &operator=(const const_iterator &o)
        { future = o.future; index = o.index; return *this; }
        inline const T &operator*() const { return future->d.resultReference(index); }
        inline const T *operator->() const { return future->d.resultPointer(index); }

        inline bool operator!=(const const_iterator &other) const
        {
            if (index == -1 && other.index == -1) // comparing end != end?
                return false;
            if (other.index == -1)
                return (future->isRunning() || (index < future->resultCount()));
            return (index != other.index);
        }

        inline bool operator==(const const_iterator &o) const { return !operator!=(o); }
        inline const_iterator &operator++() { ++index; return *this; }
        inline const_iterator operator++(int) { const_iterator r = *this; ++index; return r; }
        inline const_iterator &operator--() { --index; return *this; }
        inline const_iterator operator--(int) { const_iterator r = *this; --index; return r; }
        inline const_iterator operator+(int j) const { return const_iterator(future, index + j); }
        inline const_iterator operator-(int j) const { return const_iterator(future, index - j); }
        inline const_iterator &operator+=(int j) { index += j; return *this; }
        inline const_iterator &operator-=(int j) { index -= j; return *this; }
    private:
        JFuture const * future;
        int index;
    };
    friend class const_iterator;
    typedef const_iterator ConstIterator;

    const_iterator begin() const { return  const_iterator(this, 0); }
    const_iterator constBegin() const { return  const_iterator(this, 0); }
    const_iterator end() const { return const_iterator(this, -1); }
    const_iterator constEnd() const { return const_iterator(this, -1); }

private:
    friend class JFutureWatcher<T>;

public: // Warning: the d pointer is not documented and is considered private.
    mutable JFutureInterface<T> d;
};

template <typename T>
inline JFuture<T> &JFuture<T>::operator=(const JFuture<T> &other)
{
    d = other.d;
    return *this;
}

template <typename T>
inline T JFuture<T>::result() const
{
    d.waitForResult(0);
    return d.resultReference(0);
}

template <typename T>
inline T JFuture<T>::resultAt(int index) const
{
    d.waitForResult(index);
    return d.resultReference(index);
}

template <typename T>
inline JFuture<T> JFutureInterface<T>::future()
{
    return JFuture<T>(this);
}

J_DECLARE_SEQUENTIAL_ITERATOR(Future)

template <>
class JFuture<void>
{
public:
    JFuture()
        : d(JFutureInterface<void>::canceledResult())
    { }
    explicit JFuture(JFutureInterfaceBase *p) // internal
        : d(*p)
    { }
    JFuture(const JFuture &other)
        : d(other.d)
    { }
    ~JFuture()
    { }

    JFuture &operator=(const JFuture &other);
    bool operator==(const JFuture &other) const { return (d == other.d); }
    bool operator!=(const JFuture &other) const { return (d != other.d); }

    template <typename T>
    JFuture(const JFuture<T> &other)
        : d(other.d)
    { }

    template <typename T>
    JFuture<void> &operator=(const JFuture<T> &other)
    {
        d = other.d;
        return *this;
    }

    void cancel() { d.cancel(); }
    bool isCanceled() const { return d.isCanceled(); }

    void setPaused(bool paused) { d.setPaused(paused); }
    bool isPaused() const { return d.isPaused(); }
    void pause() { setPaused(true); }
    void resume() { setPaused(false); }
    void togglePaused() { d.togglePaused(); }

    bool isStarted() const { return d.isStarted(); }
    bool isFinished() const { return d.isFinished(); }
    bool isRunning() const { return d.isRunning(); }

    int resultCount() const { return d.resultCount(); }
    int progressValue() const { return d.progressValue(); }
    int progressMinimum() const { return d.progressMinimum(); }
    int progressMaximum() const { return d.progressMaximum(); }
    std::string progressText() const { return d.progressText(); }
    void waitForFinished() { d.waitForFinished(); }

private:
    friend class JFutureWatcher<void>;

public:
    mutable JFutureInterfaceBase d;
};

inline JFuture<void> &JFuture<void>::operator=(const JFuture<void> &other)
{
    d = other.d;
    return *this;
}

inline JFuture<void> JFutureInterface<void>::future()
{
    return JFuture<void>(this);
}

template <typename T>
JFuture<void> jToVoidFuture(const JFuture<T> &future)
{
    return JFuture<void>(future.d);
}

#endif // JFUTURE_H
